package com.norma.macaron.service.common.component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.google.common.base.Strings;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RMap;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.google.common.collect.Sets;

import javax.annotation.PostConstruct;

//@Service
public class RedissonService {

    private RedissonClient redisson;

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${REDIS_PASSWORD}")
    private String passwod;

    @PostConstruct
    public void init() {
        Config config = new Config();
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setAddress("redis://".concat(host).concat(":").concat(port));
        if(!Strings.isNullOrEmpty(passwod)){
            singleServerConfig.setPassword(passwod);
        }
        redisson = Redisson.create(config);
    }

    protected final Logger logger = LoggerFactory.getLogger(RedissonService.class);


    private static final long WEEK_SECONDS = 7 * 24 * 60 * 60;

    public static long getRemainSecondsOneDay(Date currentDate) {
        LocalDateTime midnight = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault()).plusDays(1).withHour(0).withMinute(0)
                .withSecond(0).withNano(0);
        LocalDateTime currentDateTime = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        return seconds;
    }

    /**
     * 将 key，value 存放到redis数据库中，默认设置过期时间为一周
     *
     * @param key
     * @param value
     */
    public void set(String key, Object value) {
        RBucket<String> rBucket = redisson.getBucket(key);
        logger.info(String.format("-----redis插入（set）----- key : %s   --- val : %s  ", key, value));
        rBucket.set(value.toString());
    }


    /**
     * 将 key，value 存放到redis数据库中，默认设置过期时间为一周
     *
     * @param key
     * @param value
     */
    public void setByObject(String key, Object value) {
        RBucket<String> rBucket = redisson.getBucket(key);
        logger.info(String.format("-----redis插入（setByObject）----- key : %s   --- val : %s ", key, value));
        rBucket.set(value.toString());
    }

    /**
     * 将 key，value 存放到redis数据库中
     *
     * @param key
     * @param time
     * @param value
     */
    public void setByObject(String key, Long time, Object value) {
        RBucket<Object> rBucket = redisson.getBucket(key);
        logger.info(String.format("-----redis插入（setByObject）----- key : %s   --- val : %s  --- time : %s", key, value, time));
        rBucket.set(value.toString(), time, TimeUnit.SECONDS);
    }

    /**
     * 获取 key 对应的字符串
     *
     * @param key
     * @return
     */
    public String get(String key) {
        RBucket<Object> bucket = redisson.getBucket(key);
        return bucket.get() == null ? null : bucket.get().toString();
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return
     */
    public boolean isExists(String key) {
        RBucket<Object> bucket = redisson.getBucket(key);
        return bucket.isExists();
    }


    /**
     * 以 追加map 存放到redis数据库中
     *
     * @param key
     * @param mapKey
     * @param value
     */
    public void addByMap(String mapKey, String key, Object value) {
        RMap<String, Object> map = redisson.getMap(mapKey);
        logger.info(String.format("-----redis插入（addByMap）----- mapKey : %s   --- key : %s  ", mapKey, key));
        map.put(key, value);
    }

    /**
     * 以覆盖 map 存放到redis数据库中
     *
     * @param key
     * @param mapKey
     * @param value
     */
    public void setByMap(String mapKey, String key, Object value) {
        RMap<String, Object> map = redisson.getMap(mapKey);
        map.clear();
        logger.info(String.format("-----redis插入（setByMap）----- mapKey : %s   --- key : %s  ", mapKey, key));
        map.put(key, value);
    }

    /**
     * 以追加形式 map 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void addAllByMap(String key, Map<String, Object> value) {
        RMap<String, Object> map = redisson.getMap(key);
        map.putAll(value);
        logger.info(String.format("-----redis插入（addAllByMap）----- key : %s  ", key));
    }

    /**
     * 以覆盖形式 map 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void setAllByMap(String key, Map<String, Object> value) {
        RMap<String, Object> map = redisson.getMap(key);
        map.clear();
        map.putAll(value);
        logger.info(String.format("-----redis插入（setAllByMap）----- key : %s  ", key));
    }

    /**
     * 获取 key 对应的map
     *
     * @param key
     * @return
     */
    public Map getMap(String key) {
        RMap map = redisson.getMap(key);
        return map;
    }

    /**
     * 以 Set 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void addBySet(String key, Object value) {
        RSet<Object> set = redisson.getSet(key);
        set.add(value);
        logger.info(String.format("-----redis插入（addBySet）----- key : %s  ---- val:%s ", key, value));
    }

    /**
     * 以 Set 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void setBySet(String key, Object value) {
        RSet<Object> set = redisson.getSet(key);
        set.clear();
        set.add(value);
        logger.info(String.format("-----redis插入（setBySet）----- key : %s  ---- val:%s ", key, value));
    }

    /**
     * 以 Set 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void addAllBySet(String key, Collection value) {
        RSet<Object> set = redisson.getSet(key);
        set.addAll(value);
        logger.info(String.format("-----redis插入（addAllBySet）----- key : %s  ---- val:%s ", key, value));
    }

    /**
     * 以 Set 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void setAllBySet(String key, Collection value) {
        RSet<Object> set = redisson.getSet(key);
        set.clear();
        set.addAll(value);
        logger.info(String.format("-----redis插入（setAllBySet）----- key : %s  ---- val:%s ", key, value));
    }

    /**
     * 获取set
     *
     * @param key
     */
    public Set getSet(String key) {
        RSet set = redisson.getSet(key);
        return set;
    }

    /**
     * 获取Set String类型值
     *
     * @param key
     * @return
     */
    public Set<String> getSetString(String key) {
        RSet<String> set = redisson.getSet(key);
        return set;
    }

    /**
     * 获取set中diff
     *
     * @param key
     * @param diff
     * @return
     */
    public Set<String> getSetDiff(String key, Set<String> diff) {

        RSet<String> set = redisson.getSet(key);
        if (diff == null) {
            diff = Sets.newHashSet();
        }
        logger.info(String.format("-----redis对比（getSetDiff）----- key : %s ", key));
        return Sets.difference(set, diff);// set.readDiff(diff.toArray(new String[] {}));
    }

    /**
     * 获取set中diff
     *
     * @param key
     * @param diff
     * @return
     */
    public Set<String> getSetDiff(String key, String diff) {
        return getSetDiff(key, getSetString(diff));
    }

    /**
     * 删除KEY
     *
     * @param key
     * @return
     */
    public boolean delKey(String key) {
        logger.info(String.format("-----redis删除（delKey）----- key : %s ", key));
        return redisson.getBucket(key).delete();
    }

    /**
     * 删除Set中值
     *
     * @param key
     * @param val
     * @return
     */
    public boolean delSetVal(String key, Object val) {
        logger.info(String.format("-----redis删除（delKey）----- key : %s --- val:%s", key, val));
        return redisson.getSet(key).remove(val);
    }

    /**
     * 以追加 List 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void addByList(String key, Object value) {
        logger.info(String.format("-----redis （addByList）----- key : %s --- val:%s", key, value));
        RList list = redisson.getList(key);
        list.add(value);
    }

    /**
     * 以覆盖 List 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void setByList(String key, Object value) {
        logger.info(String.format("-----redis （setByList）----- key : %s --- val:%s", key, value));
        RList list = redisson.getList(key);
        list.clear();
        list.add(value);
    }

    /**
     * 以 追加List 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void addAllByList(String key, List value) {
        logger.info(String.format("-----redis （addAllByList）----- key : %s --- val:%s", key, value));
        RList list = redisson.getList(key);
        list.addAll(value);
    }

    /**
     * 以覆盖 List 存放到redis数据库中
     *
     * @param key
     * @param value
     */
    public void setAllByList(String key, List value) {
        logger.info(String.format("-----redis （setAllByList）----- key : %s --- val:%s", key, value));
        RList list = redisson.getList(key);
        list.clear();
        list.addAll(value);
    }

    /**
     * 获取 List
     *
     * @param key
     */
    public List getList(String key) {
        RList list = redisson.getList(key);
        return list;
    }


}
